package com.triones.api.service.impl;

import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.leptage.CryptoBillScene;
import com.ruoyi.common.enums.php.OpenCardTransactionType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.SnowflakeIdWorker;
import com.ruoyi.common.utils.StringUtils;
import com.triones.api.entity.*;
import com.triones.api.entity.bo.*;
import com.triones.api.entity.param.BalanceRequestParams;
import com.triones.api.entity.param.CryptoParams;
import com.triones.api.entity.param.TotalBalanceRequestParams;
import com.triones.api.entity.vo.*;
import com.triones.api.mapper.*;
import com.triones.api.service.BankCardService;
import com.triones.api.service.CryptoWalletService;
import com.triones.api.service.FaitWalletService;
import com.triones.api.service.NoticeService;
import com.triones.api.service.third.LeptageService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 加密货币钱包 -业务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CryptoWalletServiceImpl implements CryptoWalletService {

    private final CryptoWalletMapper cryptoWalletMapper;

    private final CryptoBillMapper cryptoBillMapper;

    private final LeptageService leptageService;

    private final MemberMapper memberMapper;

    private final FaitWalletMapper faitWalletMapper;

    private final CryptoInCommonUseAddressMapper cryptoInCommonUseAddressMapper;

    private final CryptoTransferMapper cryptoTransferMapper;

    private final LeptageQuoteMapper leptageQuoteMapper;

    private final FeeThaliMapper feeThaliMapper;

    private final EcWalletBillMapper ecWalletBillMapper;

    private final LeptageGlobalAccountMapper leptageGlobalAccountMapper;

    private final CryptoExchangeMapper cryptoExchangeMapper;

    private final CryptoBeneficiaryMapper cryptoBeneficiaryMapper;

    private final CryptoBillDetailMapper cryptoBillDetailMapper;

    private final NoticeService noticeService;

    private final BankCardService bankCardService;

    private final FaitWalletService faitWalletService;

    @Override
    public List<CryptoWalletVO> apiWalletList() {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        LambdaQueryWrapper<CryptoWalletDO> lqw = Wrappers.lambdaQuery();
        lqw.eq(CryptoWalletDO::getUid, loginUser.getUserId())
            .eq(CryptoWalletDO::getStatus, "0");
        lqw.orderByDesc(CryptoWalletDO::getCreateTime);
        List<CryptoWalletVO> walletVOS = cryptoWalletMapper.selectVoList(lqw);
        Map<String, BigDecimal> result = walletVOS.stream()
            .collect(Collectors.groupingBy(
                CryptoWalletVO::getCcy,
                Collectors.reducing(
                    BigDecimal.ZERO,
                    vo -> vo.getAmount(),
                    BigDecimal::add
                )
            ));
        // 如果你需要将结果转换回 CryptoWalletVO 列表，可以这样做
        List<CryptoWalletVO> summaryList = result.entrySet().stream()
            .map(entry -> {
                CryptoWalletVO vo = new CryptoWalletVO();
                vo.setCcy(entry.getKey());
                vo.setAmount(entry.getValue());
                return vo;
            })
            .collect(Collectors.toList());
        return summaryList;
    }

    @Override
    public TableDataInfo<CryptoBillVO> apiTradePageList(CryptoParams params, PageQuery pageQuery) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        CryptoWalletVO cryptoWalletVO = cryptoWalletMapper.selectVoById(params.getCryptoId());
        if (cryptoWalletVO == null) {
            throw new ServiceException("没有查询到该货币钱包");
        }
        /**
         * 查询电子钱包
         */
        LambdaQueryWrapper<CryptoBillDO> lqw = Wrappers.lambdaQuery();
        lqw.eq(CryptoBillDO::getUid,loginUser.getUserId());
        lqw.eq(CryptoBillDO::getTransferCcy,cryptoWalletVO.getCcy())
            .eq(CryptoBillDO::getTransferChain,cryptoWalletVO.getChain());
        if (params.getTransferType() != null) {
            if ("transfer-out".equals(params.getTransferType())) {
                lqw.in(CryptoBillDO::getScene, CryptoBillScene.TRANSFER_OUT.getCode(),CryptoBillScene.TRANSFER_FIAT.getCode());
            }
            if ("transfer-in".equals(params.getTransferType())) {
                lqw.in(CryptoBillDO::getScene,CryptoBillScene.TRANSFER_IN.getCode(),CryptoBillScene.TRANSFER_CRYPTO.getCode());
            }
        }
        lqw.orderByDesc(CryptoBillDO::getCreateTime);
        Page<CryptoBillVO> result = cryptoBillMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean exchange(ExchangeBO bo) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        MemberDO memberDO = memberMapper.selectById(loginUser.getUserId());
        if (memberDO == null) {
            throw new ServiceException("当前用户不存在");
        }
        LeptageQuoteVO leptageQuoteVO = leptageQuoteMapper.selectVoById(bo.getPriceId());
        if (leptageQuoteVO == null) {
            throw new ServiceException("当前询价不存在");
        }
        if (Convert.toLong(leptageQuoteVO.getExpiredTime()) - System.currentTimeMillis() <= 0) {
            throw new ServiceException("当前询价已过有效期");
        }

        // 获取加密货币账号
        CryptoWalletDO cryptoWalletDO = cryptoWalletMapper.selectOne(new LambdaQueryWrapper<CryptoWalletDO>()
            .eq(CryptoWalletDO::getUid, loginUser.getUserId())
            .eq(CryptoWalletDO::getCcy, bo.getSellCcy())
            .eq(CryptoWalletDO::getChain, bo.getSellChain())
            .last("limit 1"));
        if (cryptoWalletDO == null) {
            throw new ServiceException("当前用户没有该币种的加密货币钱包");
        }

        // 判断余额是否足够
        BigDecimal cryptoWalletBalance = Convert.toBigDecimal(cryptoWalletDO.getAmount()).setScale(6, RoundingMode.HALF_UP);
        BigDecimal tradeAmount = bo.getSellAmount().setScale(6, RoundingMode.HALF_UP);
        if (cryptoWalletBalance.compareTo(tradeAmount) == -1) {
            throw new ServiceException("当前用户余额不足！");
        }

        // 获取法定货币账号
        FaitWalletDO faitWalletDO = faitWalletMapper.selectOne(new LambdaQueryWrapper<FaitWalletDO>()
            .eq(FaitWalletDO::getUid, loginUser.getUserId())
            .eq(FaitWalletDO::getCurrency, bo.getTargetCcy())
            .last("limit 1"));
        if (faitWalletDO == null) {
            faitWalletDO = new FaitWalletDO();
            faitWalletDO.setUid(loginUser.getUserId());
            faitWalletDO.setCurrency(bo.getTargetCcy());
            faitWalletDO.setCreateTime(System.currentTimeMillis());
            faitWalletDO.setAmount(BigDecimal.ZERO.setScale(2, BigDecimal.ROUND_HALF_UP));
            faitWalletMapper.insert(faitWalletDO);
        }

        BigDecimal faitWalletBalance = faitWalletDO.getAmount().setScale(2, BigDecimal.ROUND_HALF_UP);
        BigDecimal faitTradeAmount = tradeAmount.multiply(leptageQuoteVO.getAdditionalRate()).setScale(2, RoundingMode.DOWN);
        String requestId = Convert.toStr(SnowflakeIdWorker.generateUniqueId());

        /**
         * 保存crypto交易记录
         */
        CryptoBillDO cryptoBillDO = new CryptoBillDO();
        cryptoBillDO.setUid(loginUser.getUserId());
        cryptoBillDO.setTransferCcy(bo.getSellCcy());
        cryptoBillDO.setTransferChain(bo.getSellChain());
        cryptoBillDO.setTransferAccount(cryptoWalletDO.getAddress());
        cryptoBillDO.setTargetAccount(Convert.toStr(faitWalletDO.getId()));
        cryptoBillDO.setTargetCcy(bo.getTargetCcy());
        cryptoBillDO.setSellAmount(bo.getSellAmount());
        cryptoBillDO.setBuyAmount(faitTradeAmount);
        cryptoBillDO.setScene("transfer-fiat");
        cryptoBillDO.setStatus("SUCCEEDED");
        cryptoBillDO.setCreateTime(System.currentTimeMillis());
        cryptoBillDO.setRate(leptageQuoteVO.getPriceRate());
        cryptoBillDO.setRateId(leptageQuoteVO.getPriceId());
        cryptoBillDO.setAddedRate(leptageQuoteVO.getAdditionalRate());
        cryptoBillDO.setRequestId(requestId);
        cryptoBillDO.setFeeCcy(bo.getSellCcy());
        cryptoBillDO.setFeeAmount(bo.getSellAmount().subtract(faitTradeAmount).setScale(6, RoundingMode.DOWN));
        cryptoBillMapper.insert(cryptoBillDO);
        /**
         * crypto更新
         */
        cryptoWalletDO.setUpdateTime(System.currentTimeMillis());
        cryptoWalletDO.setAmount(cryptoWalletBalance.subtract(tradeAmount));
        cryptoWalletMapper.updateById(cryptoWalletDO);

        /**
         * 保存ec交易记录
         */
        EcWalletBillDO ecWalletBillDO = new EcWalletBillDO();
        ecWalletBillDO.setUid(memberDO.getId());
        ecWalletBillDO.setEcId(faitWalletDO.getId());
        ecWalletBillDO.setAccountHistoryNo(requestId);
        ecWalletBillDO.setAccountNo(Convert.toStr(faitWalletDO.getId()));
        ecWalletBillDO.setAmount(faitTradeAmount);
        ecWalletBillDO.setBalanceFund(faitWalletBalance.add(faitTradeAmount));
        ecWalletBillDO.setCurrency("USD");
        ecWalletBillDO.setTransactionNotes(OpenCardTransactionType.EXCHANGE.getInfo());
        ecWalletBillDO.setTxnType(OpenCardTransactionType.EXCHANGE.getCode());
        ecWalletBillDO.setTransactedAt(Convert.toStr(System.currentTimeMillis()));
        ecWalletBillDO.setStatus("success");
        ecWalletBillDO.setTransactionType("increase");
        ecWalletBillMapper.insert(ecWalletBillDO);

        /**
         * fait更新
         */
        faitWalletService.fiatWalletCardUpdate(memberDO.getId(),"USD",faitTradeAmount,"increase",null);

        /**
         * 更新lpt全球账户累计换汇数量
         */
        LeptageGlobalAccountDO globalAccount = leptageGlobalAccountMapper.selectOne(new LambdaQueryWrapper<LeptageGlobalAccountDO>()
            .eq(LeptageGlobalAccountDO::getCurrency, bo.getSellCcy()).last("limit 1"));
        if (globalAccount != null) {
            globalAccount.setCumulativeAmount(Convert.toBigDecimal(globalAccount.getCumulativeAmount(),BigDecimal.ZERO).add(tradeAmount));
            leptageGlobalAccountMapper.updateById(globalAccount);
        }

        /**
         * 并发交易成功通知
         */
        String mailContent = "Crypto提现通知";
        String subContent = "您有一笔Crypto提现交易成功，请查收。";
        noticeService.addNotice(1911687510910357505L, mailContent, subContent, cryptoBillDO.getUid());
        return true;
    }

    @Override
    public CryptoWalletVO walletDetail(String ccy, String chain) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        return cryptoWalletMapper.selectVoOne(new LambdaQueryWrapper<CryptoWalletDO>()
            .eq(CryptoWalletDO::getCcy, ccy)
            .eq(CryptoWalletDO::getChain, chain)
            .eq(CryptoWalletDO::getUid, loginUser.getUserId())
            .last("limit 1"));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean crypto(CryptoBO bo) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        MemberDO memberDO = memberMapper.selectById(loginUser.getUserId());
        if (memberDO == null) {
            throw new ServiceException("当前用户不存在");
        }
        /**
         * 转账地址
         */
        CryptoInCommonUseAddressVO commonUseAddressVO = cryptoInCommonUseAddressMapper.selectVoOne(new LambdaQueryWrapper<CryptoInCommonUseAddressDO>()
            .eq(CryptoInCommonUseAddressDO::getBeneId, bo.getBeneId())
            .eq(CryptoInCommonUseAddressDO::getStatus, "SUCCEEDED").last("limit 1"));
        if (commonUseAddressVO == null) {
            throw new ServiceException("该地址不可用");
        }
        /**
         * 获取 加密货币账号
         */
        CryptoWalletDO cryptoWalletDO = cryptoWalletMapper.selectOne(new LambdaQueryWrapper<CryptoWalletDO>()
            .eq(CryptoWalletDO::getUid, loginUser.getUserId())
            .eq(CryptoWalletDO::getCcy, commonUseAddressVO.getCcy())
            .eq(CryptoWalletDO::getChain, commonUseAddressVO.getChain())
            .last("limit 1"));
        if (cryptoWalletDO == null) {
            throw new ServiceException("当前用户没有该币种的加密货币钱包");
        }
        // 第三方提币手续费
        BigDecimal rate = BigDecimal.ZERO;
        if ("ETHEREUM".equals(commonUseAddressVO.getChain())) {
            rate = Convert.toBigDecimal(1.5);
        } else if ("TRON".equals(commonUseAddressVO.getChain())) {
            rate = Convert.toBigDecimal(1.0);
        }
        // 平台提币手续费
        BigDecimal withdrawFee = Convert.toBigDecimal(this.getCryptoWithdrawFee(commonUseAddressVO.getChain()));
        //交易金额
        BigDecimal tradeAmount = Convert.toBigDecimal(bo.getAmount()).setScale(6, RoundingMode.HALF_UP);
        //账户余额
        BigDecimal cryptoWalletBalance = Convert.toBigDecimal(cryptoWalletDO.getAmount()).setScale(6, RoundingMode.HALF_UP);
        //实际到账额度
        BigDecimal targetAmount = tradeAmount.subtract(withdrawFee);
        if (cryptoWalletBalance.compareTo(tradeAmount) == -1) {
            throw new ServiceException("账户余额不足！");
        }
        /**
         * 提币到账校验（不能低于扣费总额）
         */
        if (tradeAmount.compareTo(withdrawFee) == -1) {
            throw new ServiceException("提币数量不能低于或等于手续费用！");
        }
        String requestId = Convert.toStr(SnowflakeIdWorker.generateUniqueId());
        /**
         * 保存 加密货币账单（出入账）
         */
        CryptoBillDO cryptoBillDO = new CryptoBillDO();
        cryptoBillDO.setUid(memberDO.getId());
        cryptoBillDO.setTransferCcy(cryptoWalletDO.getCcy());
        cryptoBillDO.setTransferAccount(cryptoWalletDO.getAddress());
        cryptoBillDO.setTransferChain(cryptoWalletDO.getChain());
        cryptoBillDO.setTargetAccount(commonUseAddressVO.getAddress());
        cryptoBillDO.setTargetCcy(commonUseAddressVO.getCcy());
        cryptoBillDO.setTargetChain(commonUseAddressVO.getChain());
        cryptoBillDO.setSellAmount(tradeAmount);
        cryptoBillDO.setBuyAmount(targetAmount);
        cryptoBillDO.setScene("transfer-out");
        cryptoBillDO.setStatus("CONFIRMING");
        cryptoBillDO.setCreateTime(System.currentTimeMillis());
        cryptoBillDO.setFeeCcy(cryptoWalletDO.getCcy());
        cryptoBillDO.setFeeAmount(withdrawFee);
        cryptoBillDO.setRequestId(requestId);
        cryptoBillDO.setRate(rate);
        cryptoBillMapper.insert(cryptoBillDO);

        //划转
        TransferRequestBodyBO bodyBO = new TransferRequestBodyBO();
        bodyBO.setCcy(cryptoBillDO.getTransferCcy());
        bodyBO.setChain(cryptoBillDO.getTargetChain());
        bodyBO.setAmount(Convert.toStr(targetAmount.add(rate)));
        this.transfer(bodyBO, "IN", memberDO.getId());

        // 发送提币交易申请
        CryptoRequestBodyBO cryptoRequestBodyBO = new CryptoRequestBodyBO();
        cryptoRequestBodyBO.setRequestId(requestId);
        cryptoRequestBodyBO.setAmount(Convert.toStr(targetAmount.add(rate)));
        cryptoRequestBodyBO.setCcy(commonUseAddressVO.getCcy());
        cryptoRequestBodyBO.setChain(commonUseAddressVO.getChain());
        cryptoRequestBodyBO.setAddress(commonUseAddressVO.getAddress());
        Map cryptoResponseMap = leptageService.crypto(cryptoRequestBodyBO, memberDO.getAccountId());
        if (cryptoResponseMap == null) {
            throw new ServiceException("交易失败，请稍后重试");
        }
        return true;
    }

    @Override
    public List<CryptoInCommonUseAddressVO> inCommonUseAddressPageList(String ccy, String chain, String keyword) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        LambdaQueryWrapper<CryptoInCommonUseAddressDO> lqw = new LambdaQueryWrapper<CryptoInCommonUseAddressDO>();
        lqw.eq(CryptoInCommonUseAddressDO::getUid,loginUser.getUserId())
        .eq(CryptoInCommonUseAddressDO::getDel,"0")
        .eq(CryptoInCommonUseAddressDO::getCcy,ccy)
        .eq(CryptoInCommonUseAddressDO::getChain,chain)
        .like(StringUtils.isNotBlank(keyword),CryptoInCommonUseAddressDO::getAddress,keyword).or()
            .like(StringUtils.isNotBlank(keyword),CryptoInCommonUseAddressDO::getNickName,keyword)
        .orderByDesc(CryptoInCommonUseAddressDO::getCreateAt);
        return cryptoInCommonUseAddressMapper.selectVoList(lqw);
    }

    @Override
    public boolean mockDepositCrypto(CryptoWalletDO dto) {
        CryptoWalletRequestBodyBO cryptoWalletRequestBodyBO = new CryptoWalletRequestBodyBO();
        cryptoWalletRequestBodyBO.setCcy(dto.getCcy());
        cryptoWalletRequestBodyBO.setChain(dto.getChain());
        cryptoWalletRequestBodyBO.setAddress(dto.getAddress());
        cryptoWalletRequestBodyBO.setAmount(Convert.toStr(dto.getAmount()));
        cryptoWalletRequestBodyBO.setSucceed(true);
        boolean result = leptageService.mockDepositCrypto(cryptoWalletRequestBodyBO);
        return result;
    }

    @Override
    public List<Map> mockBalance(String accountId) {
        BalanceRequestParams balanceRequestParams = new BalanceRequestParams();
        balanceRequestParams.setCcy("USDT");
        balanceRequestParams.setChain("ETHEREUM");
        List<Map> result = leptageService.mockBalance(balanceRequestParams,accountId);
        return result;
    }

    @Override
    public CryptoBillVO apiTradeDetail(Long id) {
        return cryptoBillMapper.selectVoById(id);
    }

    @Override
    public Boolean mockWithdrawCrypto(WithdrawCryptoRequstBodyBO bo) {
        return leptageService.mockWithdrawCrypto(bo);
    }

    @Override
    public Boolean transfer(TransferRequestBodyBO bo,String direction,Long uid) {
        MemberDO memberDO = memberMapper.selectById(uid);
        if (memberDO == null) {
            throw new ServiceException("当前用户不存在");
        }
        String requestId = Convert.toStr(SnowflakeIdWorker.generateUniqueId());
        bo.setRequestId(requestId);
        Map transfer = leptageService.transfer(bo,memberDO.getAccountId(),direction);
        if (transfer == null) {
            throw new ServiceException("操作失败");
        }
        Map money = (Map) transfer.get("money");
        CryptoTransferDO cryptoTransferDO = new CryptoTransferDO();
        cryptoTransferDO.setUid(uid);
        cryptoTransferDO.setAccountId(memberDO.getAccountId());
        cryptoTransferDO.setRequestId(requestId);
        cryptoTransferDO.setDirection(direction);
        cryptoTransferDO.setCcy(bo.getCcy());
        cryptoTransferDO.setChain(bo.getChain());
        cryptoTransferDO.setAmount(bo.getAmount());
        cryptoTransferDO.setTxnId(Convert.toStr(transfer.get("txnId")));
        cryptoTransferDO.setStatus(Convert.toStr(transfer.get("status")));
        cryptoTransferDO.setCreatedAt(Convert.toStr(System.currentTimeMillis()));
        cryptoTransferDO.setUpdatedAt(Convert.toStr(System.currentTimeMillis()));
        cryptoTransferDO.setCompletedAt(Convert.toStr(System.currentTimeMillis()));
        if (money != null) {
            cryptoTransferDO.setProtocol(Convert.toStr(money.get("protocol")));
        }
        return cryptoTransferMapper.insert(cryptoTransferDO) > 0;
    }

    @Override
    public List<CryptoWalletVO> apiChainWalletList(String ccy) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new ServiceException("当前用户退出登录!");
        }
        LambdaQueryWrapper<CryptoWalletDO> lqw = Wrappers.lambdaQuery();
        lqw.eq(CryptoWalletDO::getUid, loginUser.getUserId())
            .eq(CryptoWalletDO::getCcy, ccy)
            .eq(CryptoWalletDO::getStatus, "0");
        lqw.orderByDesc(CryptoWalletDO::getCreateTime);
        return cryptoWalletMapper.selectVoList(lqw);
    }

    @Override
    public LeptageQuoteDO leptageQuote(LeptageQuoteBO bo) {
        LptQuoteRequestBodyBO lptQuoteRequestBodyBO = new LptQuoteRequestBodyBO();
        lptQuoteRequestBodyBO.setCcyPair(bo.getSellCcy() + "-" + bo.getTargetCcy());
        Map quoteResponseMap = leptageService.lptQuote(lptQuoteRequestBodyBO);
        if (quoteResponseMap == null) {
            throw new ServiceException("询价失败，请稍后重试");
        }
        BigDecimal rate = Convert.toBigDecimal(quoteResponseMap.get("rate"));
        LeptageQuoteDO leptageQuoteDO = new LeptageQuoteDO();
        leptageQuoteDO.setSellCcy(bo.getSellCcy());
        leptageQuoteDO.setSellChain(bo.getSellChain());
        leptageQuoteDO.setTargetCcy(bo.getTargetCcy());
        leptageQuoteDO.setPriceId(Convert.toStr(quoteResponseMap.get("id")));
        leptageQuoteDO.setQuoteObj(bo.getQuoteObj());
        leptageQuoteDO.setPriceRate(rate);
        leptageQuoteDO.setAdditionalRate(rate);
        leptageQuoteDO.setCurrentTime(Convert.toStr(quoteResponseMap.get("currentTime")));
        leptageQuoteDO.setExpiredTime(Convert.toStr(quoteResponseMap.get("expiredTime")));
        if ("member".equals(bo.getQuoteObj())) {
            FeeThaliVO feeThaliVO = feeThaliMapper.selectVoOne(new LambdaQueryWrapper<FeeThaliDO>()
                .eq(FeeThaliDO::getType, "exchange")
                .eq(FeeThaliDO::getStatus, "0").last("limit 1"));
            if (feeThaliVO != null) {
                BigDecimal additionalRate = Convert.toBigDecimal(feeThaliVO.getFeeConfig()).divide(new BigDecimal(1000));
                //获客
                if ("marketing".equals(feeThaliVO.getSubType())) {
                    leptageQuoteDO.setAdditionalRate(rate.add(additionalRate));
                }
                // 获利
                if ("profit".equals(feeThaliVO.getSubType())) {
                    leptageQuoteDO.setAdditionalRate(rate.subtract(additionalRate));
                }
            }
        }
        leptageQuoteMapper.insert(leptageQuoteDO);
        return leptageQuoteDO;
    }

    @Override
    public List<Map> totalBalance(String ccy) {
        TotalBalanceRequestParams params = new TotalBalanceRequestParams();
        params.setCcy(ccy);
        return leptageService.totalBalance(params);
    }

    @Override
    public Map totalExchange(String ccyPair, String sellAmount) {
        LptQuoteRequestBodyBO lptQuoteRequestBodyBO = new LptQuoteRequestBodyBO();
        lptQuoteRequestBodyBO.setCcyPair(ccyPair);
        Map quoteResponseMap = leptageService.lptQuote(lptQuoteRequestBodyBO);
        if (quoteResponseMap != null) {
            LptExchangeRequestBodyBO lptExchangeRequestBodyBO = new LptExchangeRequestBodyBO();
            lptExchangeRequestBodyBO.setCcyPair(ccyPair);
            lptExchangeRequestBodyBO.setPriceId(Convert.toStr(quoteResponseMap.get("id")));
            lptExchangeRequestBodyBO.setPrice(Convert.toStr(quoteResponseMap.get("rate")));
            lptExchangeRequestBodyBO.setSellAmount(sellAmount);
            return leptageService.lptExchange(lptExchangeRequestBodyBO);
        }
        return null;
    }

    @Override
    public String getCryptoWithdrawFee(String chain) {
        FeeThaliVO feeThaliVO = feeThaliMapper.selectVoOne(new LambdaQueryWrapper<FeeThaliDO>()
            .eq(FeeThaliDO::getType, "crypto_withdraw")
            .eq(FeeThaliDO::getSubType, chain)
            .eq(FeeThaliDO::getStatus, "0")
            .last("limit 1"));
        if (feeThaliVO != null) {
            return feeThaliVO.getFeeConfig();
        } else {
            throw new ServiceException("暂不支持提币操作！");
        }
    }

    @Override
    public void exchange(String ccyPair, String sellAmount, Long quoteId) {
        LeptageQuoteVO leptageQuoteVO = leptageQuoteMapper.selectVoById(quoteId);
        if (leptageQuoteVO != null) {
            if (Convert.toLong(leptageQuoteVO.getExpiredTime()) - System.currentTimeMillis() > 0) {
                LptExchangeRequestBodyBO lptExchangeRequestBodyBO = new LptExchangeRequestBodyBO();
                lptExchangeRequestBodyBO.setCcyPair(ccyPair);
                lptExchangeRequestBodyBO.setPriceId(leptageQuoteVO.getPriceId());
                lptExchangeRequestBodyBO.setPrice(Convert.toStr(leptageQuoteVO.getPriceRate()));
                lptExchangeRequestBodyBO.setSellAmount(sellAmount);
                Map map = leptageService.lptExchange(lptExchangeRequestBodyBO);
                if (map != null) {
                    CryptoExchangeDO cryptoExchangeDO = new CryptoExchangeDO();
                    cryptoExchangeDO.setCcyPair(ccyPair);
                    cryptoExchangeDO.setPriceId(leptageQuoteVO.getPriceId());
                    cryptoExchangeDO.setPrice(Convert.toStr(leptageQuoteVO.getPriceRate()));
                    cryptoExchangeDO.setSellAmount(sellAmount);
                    cryptoExchangeDO.setBuyAmount(Convert.toStr(map.get("buyAmount")));
                    cryptoExchangeDO.setTxnId(Convert.toStr(map.get("txnId")));
                    cryptoExchangeDO.setStatus(Convert.toStr(map.get("status")));
                    cryptoExchangeDO.setCreatedAt(Convert.toStr(map.get("createdAt")));
                    cryptoExchangeDO.setSettledAt(Convert.toStr(map.get("settledAt")));
                    cryptoExchangeMapper.insert(cryptoExchangeDO);
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sysWithdraw(String walletCcy, String payoutCcy, String walletAmount) {

        CryptoBeneficiaryVO beneficiaryVO = cryptoBeneficiaryMapper.selectVoOne(new LambdaQueryWrapper<CryptoBeneficiaryDO>().last("limit 1"));
        if (beneficiaryVO != null) {
            // 保存系统提现申请
            String requestId = Convert.toStr(SnowflakeIdWorker.generateUniqueId());
            CryptoSysBillDO cryptoSysBillDO = new CryptoSysBillDO();
            cryptoSysBillDO.setRequestId(requestId);
            cryptoSysBillDO.setStatus("PENDING");
            cryptoSysBillDO.setWithdrawalMoneyCcy(walletCcy);
            cryptoSysBillDO.setWithdrawalMoneyAmount(Convert.toBigDecimal(walletAmount));
            cryptoSysBillDO.setPayoutMoneyCcy(payoutCcy);
            cryptoSysBillDO.setBeneId(beneficiaryVO.getBeneId());
            cryptoSysBillDO.setCreatedAt(Convert.toStr(System.currentTimeMillis()));
            cryptoBillDetailMapper.insert(cryptoSysBillDO);

            LptWithdrawRequestBodyBO lptWithdrawRequestBodyBO = new LptWithdrawRequestBodyBO();
            lptWithdrawRequestBodyBO.setRequestId(requestId);
            lptWithdrawRequestBodyBO.setWalletCcy(walletCcy);
            lptWithdrawRequestBodyBO.setWalletAmount(walletAmount);
            lptWithdrawRequestBodyBO.setPayoutCcy(payoutCcy);
            lptWithdrawRequestBodyBO.setBeneId(beneficiaryVO.getBeneId());
            lptWithdrawRequestBodyBO.setPaymentMethod("SWIFT");
            lptWithdrawRequestBodyBO.setFeeBear("SHARE");
            Map map = leptageService.lptWithdraw(lptWithdrawRequestBodyBO);
            log.info("系统提现申请：{}", map);
        } else {
            log.info("没有查询到php VA 账户收款人信息！！！");
        }
    }
}
